package com.lagou.edu.factory;

import com.lagou.edu.anno.Autowired;
import com.lagou.edu.anno.Component;
import com.lagou.edu.anno.Transactional;
import com.mysql.jdbc.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author luohq
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    private static Map<String, Object> map = new HashMap<>();

    static {
        try {
            Reflections reflections = new Reflections("com.lagou.edu");
            //先生成component的bean
            Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Component.class);

            for (Class<?> componentClass : typesAnnotatedWith) {
                Object componentObject = componentClass.getDeclaredConstructor().newInstance();
                Component annotation = componentClass.getAnnotation(Component.class);
                if (StringUtils.isEmptyOrWhitespaceOnly(annotation.value())) {
                    String[] name = componentClass.getName().split("\\.");
                    map.put(name[name.length - 1], componentObject);
                } else {
                    map.put(annotation.value(), componentObject);
                }

            }
            //在处理Autowired的注入
            for (String key : map.keySet()) {
                Object targetObject = map.get(key);
                Class<?> c = targetObject.getClass();
                Field[] declaredFields = c.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    if (declaredField.isAnnotationPresent(Autowired.class)) {
                        Object needWiredObject = BeanFactory.getBeanByType(declaredField.getType());
                        if (null == needWiredObject) {
                            throw new RuntimeException("需要注入的类型未找到"+ declaredField.getType());
                        }
                        declaredField.setAccessible(true);
                        declaredField.set(targetObject, needWiredObject);
                    }


                }

            }
            //在处理的注入Transactional
            for (String key : map.keySet()) {
                Object targetObject = map.get(key);
                Class<?> c = targetObject.getClass();
                if (c.isAnnotationPresent(Transactional.class)) {
                    ProxyFactory proxyFactory = (ProxyFactory) map.get("ProxyFactory");
                    Class<?>[] interfaces = c.getInterfaces();
                    Object proxyObject;
                    if (interfaces != null && interfaces.length > 0) {
                        proxyObject = proxyFactory.getJdkProxy(targetObject);
                    } else {
                        proxyObject = proxyFactory.getCglibProxy(targetObject);
                    }
                    map.put(key, proxyObject);
                }
            }

        } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public static Object getBean(String name){
        return map.get(name);
    }

    public static Object getBeanByType(Class<?> c){
        for (String key : map.keySet()) {
            Object o = map.get(key);
            if(c.isInstance(o)){
                return o;
            }
        }
        return null;
    }
}
